using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.LowLevel;

namespace JH
{
    /// <summary>
    ///  线程的调度器
    /// </summary>
    public static class ThreadDispatcher
    {
        /// <summary>
        ///  其他线程单次判定间隔
        /// </summary>
        private const int LoopInterval = 10;

        /// <summary>
        /// 主线程ID标记
        /// </summary>
        private static int _mainThreadId;

        /// <summary>
        /// 判断当前线程是否为主线程
        /// </summary>
        public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == _mainThreadId;

        /// <summary>
        ///  当前帧数
        /// </summary>
        public static ulong FrameCount { get; private set; }

        /// <summary>
        /// 待执行的回调队列
        ///  1. Func{bool} 为判断条件,能否执行Action
        ///  2. Action 为需要执行的回调
        /// </summary>
        private static readonly ConcurrentQueue<(Func<bool> canInvoke, Action action)> Actions = new();

        /// <summary>
        /// 当前帧判定为不满足条件执行的回调队列
        /// </summary>
        private static readonly ConcurrentQueue<(Func<bool> canInvoke, Action action)> RemainActions = new();

        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        private static void Initialize()
        {
            _mainThreadId = Thread.CurrentThread.ManagedThreadId;

            // 获取当前PlayerLoop
            var playerLoop = PlayerLoop.GetCurrentPlayerLoop();

            // 创建自定义系统
            var customSystem = new PlayerLoopSystem
            {
                type = typeof(CustomUpdate),
                updateDelegate = RunQueuedActions,
            };

            // 插入到PlayerLoop中
            var newSubSystems = new List<PlayerLoopSystem>(playerLoop.subSystemList)
            {
                customSystem
            };
            playerLoop.subSystemList = newSubSystems.ToArray();

            // 设置修改后的PlayerLoop
            PlayerLoop.SetPlayerLoop(playerLoop);
        }

        /// <summary>
        /// 执行队列中的Action
        /// </summary>
        private static void RunQueuedActions()
        {
            FrameCount++;

            if (Actions.Count == 0 && RemainActions.Count == 0) return;

            int remainCount = RemainActions.Count;
            for (int i = 0; i < remainCount; i++)
            {
                if (RemainActions.TryDequeue(out var record))
                {
                    if (record.canInvoke())
                        record.action();
                    else
                        RemainActions.Enqueue(record);
                }
            }

            int actionCount = Actions.Count;
            for (int i = 0; i < actionCount; i++)
            {
                if (Actions.TryDequeue(out var action))
                {
                    if (action.canInvoke())
                        action.action();
                    else
                        RemainActions.Enqueue(action);
                }
            }
        }

        /// <summary>
        ///  调用回调
        /// </summary>
        public static void Invoke(Func<bool> canInvoke, Action action, DispatchState state = default)
        {
            // 如果设置为主线程则在主线程调用
            if (state == DispatchState.MainThread)
            {
                InvokeInMainThread(canInvoke, action);
                return;
            }

            // 如果设置为其他线程则在其他线程调用
            if (state == DispatchState.OtherThread)
            {
                Debug.Log("InvokeInOtherThread");
                InvokeInOtherThread(canInvoke, action);
                return;
            }

            // 默认情况下，如果在主线程则在主线程调用，否则在其他线程调用
            if (IsMainThread) InvokeInMainThread(canInvoke, action);
            else InvokeInOtherThread(canInvoke, action);
        }

        /// <summary>
        ///  在主线程中调用回调
        /// </summary>
        private static void InvokeInMainThread(Func<bool> canInvoke, Action action)
        {
            Actions.Enqueue((canInvoke, action));
        }

        /// <summary>
        ///  在其他线程中调用回调
        /// </summary>
        private static void InvokeInOtherThread(Func<bool> canInvoke, Action invokeContinuation)
        {
            Task.Run(async () =>
            {
                if (canInvoke == null)
                {
                    invokeContinuation?.Invoke();
                    return;
                }

                while (!canInvoke()) await Task.Delay(LoopInterval);
                invokeContinuation();
            }).ContinueWith(t =>
            {
                if (t.IsFaulted && t.Exception != null)
                {
                    // 提取并抛出第一个异常
                    var flattenedException = t.Exception.Flatten();
                    
                    // 原始异常
                    throw flattenedException.InnerException ?? t.Exception;
                }
            });
        }

        private struct CustomUpdate
        {
        }
    }
}